/*
 * Copyright 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cz.zcu.fav.ratdroid.activity.calendar.day;

import java.util.ArrayList;

import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;

import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import cz.zcu.fav.ratdroid.R;
import cz.zcu.fav.ratdroid.activity.ObjectBrowserActivity;
import cz.zcu.fav.ratdroid.activity.calendar.CalendarActivity;
import cz.zcu.fav.ratdroid.activity.calendar.provider.ICalendarDataProvider;
import cz.zcu.fav.ratdroid.activity.calendar.reservation.CreateReservationActivity;
import cz.zcu.fav.ratdroid.activity.calendar.reservation.EditReservationActivity;
import cz.zcu.fav.ratdroid.activity.calendar.reservation.ReservationFactory;
import cz.zcu.fav.ratdroid.activity.calendar.reservation.ViewReservationActivity;
import cz.zcu.fav.ratdroid.bean.Object;
import cz.zcu.fav.ratdroid.bean.Period;
import cz.zcu.fav.ratdroid.bean.Reservation;
import cz.zcu.fav.ratdroid.bean.Reservations;
import cz.zcu.fav.ratdroid.service.IRestListener;
import cz.zcu.fav.ratdroid.service.RestTask;

/**
 * Shows a pageable calendar of all days. The primary UI classes for rendering
 * the calendar are
 * {@link com.google.android.apps.iosched.ui.widget.TimeRulerView},
 * {@link BlocksLayout}, and {@link BlockView}.
 */
public class ScheduleFragment extends Fragment implements View.OnClickListener,
		IRestListener<Reservations>, OnTouchListener, OnLongClickListener
{
	public static String LOADED_COLUMNS = "loaded.columns";
	private static final int AUTOSCROLL_HOUR = 6;
	private Workspace mWorkspace;
	private TextView mTitle;
	private TextView block_period_count;
	private int mTitleCurrentDayIndex = -1;
	private boolean recreated = false;
	private ICalendarDataProvider asyncDataProvider;
	private Day day = new Day();
	private LocalDate preselectedDate;
	private RestTask<Reservations> scheduleTask;

	@SuppressWarnings("unchecked")
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		if (savedInstanceState != null)
		{
			recreated = true;
			columns = (ArrayList<Column>) savedInstanceState
					.getSerializable(LOADED_COLUMNS);
		}
		asyncDataProvider = (ICalendarDataProvider) getArguments()
				.getSerializable(
						ICalendarDataProvider.CALENDAR_DATA_PROVIDER_IDENTIFIER);
		preselectedDate = (LocalDate) getArguments().getSerializable(
				DayActivity.PRESELECTED_DATE);
		setHasOptionsMenu(true);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState)
	{
		ViewGroup root = (ViewGroup) inflater.inflate(
				R.layout.fragment_schedule, null);

		mWorkspace = (Workspace) root.findViewById(R.id.workspace);

		mTitle = (TextView) root.findViewById(R.id.block_title);
		block_period_count = (TextView) root
				.findViewById(R.id.block_period_count);
		setupDay(inflater, preselectedDate);

		updateWorkspaceHeader(0);

		if (!recreated)
		{
			revalidate();
		} else
		{
			if (columns != null)
			{
				setBlocks();
			}
		}

		// Autoscroll to predefined hour
		final TimeSheetScrollView scrollView = (TimeSheetScrollView) day
				.getScrollView();
		scrollView.post(new Runnable()
		{
			public void run()
			{
				scrollView.scrollTo(0,
						scrollView.getHourPosition(AUTOSCROLL_HOUR));
			}
		});

		return root;
	}

	private void revalidate()
	{
		day.getBlocksView().removeAllBlocks();
		scheduleTask = asyncDataProvider.getReservations(this.getActivity(),
				preselectedDate.toDateTimeAtStartOfDay().toLocalDateTime(),
				preselectedDate.toDateTimeAtStartOfDay().plusDays(1)
						.minusMinutes(1).toLocalDateTime(), this);
	}

	@Override
	public void onDestroy()
	{
		if (scheduleTask != null)
		{
			scheduleTask.setContext(null);
		}
		super.onDestroy();
	}

	private void setBlocks()
	{
		day.getBlocksView().setColumns(columns.size());
		day.getBlocksView().setColumnsList(columns);
		int blockcount = 0;
		// and now we can create corresponding blocks
		for (int i = 0; i < columns.size(); i++)
		{
			for (Period period : columns.get(i).getPeriods())
			{

				final BlockView blockView = asyncDataProvider.getBlock(
						getActivity(), period.getReservation().getObjectName(),
						i, period, preselectedDate);
				blockView.setOnClickListener(this);
				day.getBlocksView().addBlock(blockView);
				blockcount++;
			}
		}
		
		block_period_count.setText(blockcount + "");
	}

	public void updateWorkspaceHeader(int dayIndex)
	{
		if (mTitleCurrentDayIndex == dayIndex)
		{
			return;
		}

		mTitleCurrentDayIndex = dayIndex;

		mTitle.setText(DateFormat.getDateFormat(getActivity()).format(
				preselectedDate.toDate()));
	}

	private void setupDay(LayoutInflater inflater, LocalDate date)
	{
		Day day = new Day();

		// Setup data

		day.setIndex(1);
		day.setDate(date);
		// Setup views
		day.setRootView((ViewGroup) inflater.inflate(R.layout.blocks_content,
				null));

		day.getRootView().setOnTouchListener(this);
		day.setScrollView((TimeSheetScrollView) day.getRootView().findViewById(
				R.id.blocks_scroll));

		day.setBlocksView((BlocksLayout) day.getRootView().findViewById(
				R.id.blocks));
		day.getBlocksView().setOnTouchListener(this);
		day.getBlocksView().setOnLongClickListener(this);

		day.setNowView(day.getRootView().findViewById(R.id.blocks_now));

		day.getBlocksView().setDrawingCacheEnabled(true);
		day.getBlocksView().setAlwaysDrawnWithCacheEnabled(true);

		mWorkspace.addView(day.getRootView());
		this.day = day;
	}

	@Override
	public void onSaveInstanceState(Bundle outState)
	{
		outState.putSerializable(LOADED_COLUMNS, columns);
		super.onSaveInstanceState(outState);
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState)
	{
		super.onActivityCreated(savedInstanceState);
		getActivity().runOnUiThread(new Runnable()
		{
			public void run()
			{
				updateNowView(true);
			}
		});
	}

	/** {@inheritDoc} */
	public void onClick(View view)
	{

		if (view instanceof BlockView)
		{
			Intent obj;
			BlockView block = (BlockView) view;
			// for current user reservations allow editing
			if (block.isCurrentUserReservation(getActivity())
					&& block.isEditable())
			{
				obj = new Intent(getActivity(), EditReservationActivity.class);
			} else
			{
				obj = new Intent(getActivity(), ViewReservationActivity.class);
			}
			obj.putExtra(Period.SINGLE_PERIOD_IDENTIFIER, block.getPeriod());
			startActivityForResult(obj,
					CalendarActivity.INVALIDATE_CALENDAR_RESULT_KEY);
		}
	}

	/**
	 * Update position and visibility of "now" view.
	 */
	private boolean updateNowView(boolean forceScroll)
	{
		if (day != null && forceScroll)
		{
			// Scroll to show "now" in center
			mWorkspace.setCurrentScreen(day.getIndex());
			final int offset = day.getScrollView().getHeight() / 2;
			day.getNowView().requestRectangleOnScreen(
					new Rect(0, offset, 0, offset), true);
			day.getBlocksView().requestLayout();
			return true;
		}

		return false;
	}

	private ArrayList<Column> columns;

	public void notifyDataLoaded(Reservations data)
	{
		scheduleTask = null;
		// MOCKITY MOCK
		// data = new Reservations();
		// List<Reservation> reservations = new ArrayList<Reservation>();
		// Reservation res = new Reservation();
		// Period per = new Period();
		// per.setId(1);
		// per.setPickAction(PickAction.PICKED);
		// per.setReturnAction(ReturnAction.RETURNED);
		// per.setFromDate(LocalDateTime.now());
		// per.setToDate(LocalDateTime.now().plusHours(2));
		// per.setValid(true);
		// per.setReservation(res);
		// List<Period> periods = new ArrayList<Period>();
		// periods.add(per);
		// res.setPeriods(periods);
		// res.setObjectName("nakej objekt");
		// res.setUserName("nakej user");
		// reservations.add(res);
		// data.setReservations(reservations);

		if (data != null)
		{
			ReservationFactory.joinReservationToPeriods(data);

			columns = new ArrayList<Column>();
			columns.add(new Column());

			// Lets sort all incoming periods to columns first
			for (Reservation reservation : data.getReservations())
			{
				for (Period period : reservation.getPeriods())
				{
					boolean wasAdded = false;

					for (Column column : columns)
					{
						if (column.addNewPeriod(period))
						{
							wasAdded = true;
							break;
						}
					}
					if (!wasAdded)
					{
						Column newColumn = new Column();
						newColumn.addNewPeriod(period);
						columns.add(newColumn);
					}
				}
			}

			setBlocks();
		}

	}

	public void notifyException(final Exception ex)
	{
		scheduleTask = null;
		getActivity().runOnUiThread(new Runnable()
		{

			public void run()
			{
				Toast.makeText(ScheduleFragment.this.getActivity(),
						ex.getMessage(), Toast.LENGTH_SHORT).show();
			}
		});
	}

	private float lastCoordinatesY = 0;
	private int lastSelectedHour = 0;

	public boolean onTouch(View v, MotionEvent event)
	{
		if (event.getAction() == MotionEvent.ACTION_DOWN)
		{
			lastCoordinatesY = event.getY();
		}
		// do not consume this one
		return false;
	}

	public boolean onLongClick(View v)
	{
		lastSelectedHour = (int) Math.floor(lastCoordinatesY
				/ (v.getHeight() / 24));
		LocalTime selectedTime = new LocalTime(lastSelectedHour, 0);
		LocalDateTime selectedDateTime = preselectedDate.toDateTime(
				selectedTime).toLocalDateTime();
		// we dont want any action on dates which are already out of scope - in
		// the past
		LocalTime currentTimeWithoutMinutes = new LocalTime(LocalTime.now()
				.getHourOfDay(), 0);
		LocalDateTime currentDateTimeWithoutMinutes = LocalDate.now()
				.toLocalDateTime(currentTimeWithoutMinutes);

		if (!selectedDateTime.isBefore(currentDateTimeWithoutMinutes))
		{
			Object object = asyncDataProvider.provideObject();
			if (object == null)
			{
				// start object browser and find our object
				Intent obj = new Intent(getActivity(),
						ObjectBrowserActivity.class);

				startActivityForResult(obj,
						ObjectBrowserActivity.OBJECT_BROWSER_REQUEST_CODE);
			} else
			{
				createReservation(object);
			}
		}
		return true;
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		if (requestCode == ObjectBrowserActivity.OBJECT_BROWSER_REQUEST_CODE)
		{
			if (resultCode == android.app.Activity.RESULT_OK)
			{
				Object result = (Object) data
						.getSerializableExtra(Object.SINGLE_OBJECT_IDENTIFIER);
				createReservation(result);
			}
		} else if (requestCode == CalendarActivity.INVALIDATE_CALENDAR_RESULT_KEY)
		{
			if (resultCode == android.app.Activity.RESULT_OK)
			{
				revalidate();
				// revalidate fragment

			}
		}
	}

	private void createReservation(Object result)
	{
		Intent intent = new Intent(getActivity(),
				CreateReservationActivity.class);
		LocalTime selectedTime = new LocalTime(lastSelectedHour, 0);
		LocalDateTime selectedDateTime = preselectedDate.toDateTime(
				selectedTime).toLocalDateTime();
		// just in case when user wants to make reservation "now"
		if (selectedDateTime.isBefore(LocalDateTime.now()))
		{
			selectedDateTime = LocalDateTime.now();
		}
		intent.putExtra(DayActivity.PRESELECTED_DATETIME, selectedDateTime);
		intent.putExtra(Object.SINGLE_OBJECT_IDENTIFIER, result);
		startActivityForResult(intent,
				CalendarActivity.INVALIDATE_CALENDAR_RESULT_KEY);
	}

}
